//
//  JRMASConstraintBuilder.m
//  JRMASonry
//
//  Created by Jonas Budelmann on 20/07/13.
//  Copyright (c) 2013 cloudling. All rights reserved.
//

#import "JRMASConstraintMaker.h"
#import "JRMASViewConstraint.h"
#import "JRMASCompositeConstraint.h"
#import "JRMASConstraint+Private.h"
#import "JRMASViewAttribute.h"
#import "View+JRMASAdditions.h"

@interface JRMASConstraintMaker () <JRMASConstraintDelegate>

@property (nonatomic, weak) JRMAS_VIEW *view;
@property (nonatomic, strong) NSMutableArray *constraints;

@end

@implementation JRMASConstraintMaker

- (id)initWithView:(JRMAS_VIEW *)view {
    self = [super init];
    if (!self) return nil;
    
    self.view = view;
    self.constraints = NSMutableArray.new;
    
    return self;
}

- (NSArray *)install {
    if (self.removeExisting) {
        NSArray *installedConstraints = [JRMASViewConstraint installedConstraintsForView:self.view];
        for (JRMASConstraint *constraint in installedConstraints) {
            [constraint uninstall];
        }
    }
    NSArray *constraints = self.constraints.copy;
    for (JRMASConstraint *constraint in constraints) {
        constraint.updateExisting = self.updateExisting;
        [constraint install];
    }
    [self.constraints removeAllObjects];
    return constraints;
}

#pragma mark - JRMASConstraintDelegate

- (void)constraint:(JRMASConstraint *)constraint shouldBeReplacedWithConstraint:(JRMASConstraint *)replacementConstraint {
    NSUInteger index = [self.constraints indexOfObject:constraint];
    NSAssert(index != NSNotFound, @"Could not find constraint %@", constraint);
    [self.constraints replaceObjectAtIndex:index withObject:replacementConstraint];
}

- (JRMASConstraint *)constraint:(JRMASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
    JRMASViewAttribute *viewAttribute = [[JRMASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute];
    JRMASViewConstraint *newConstraint = [[JRMASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute];
    if ([constraint isKindOfClass:JRMASViewConstraint.class]) {
        //replace with composite constraint
        NSArray *children = @[constraint, newConstraint];
        JRMASCompositeConstraint *compositeConstraint = [[JRMASCompositeConstraint alloc] initWithChildren:children];
        compositeConstraint.delegate = self;
        [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint];
        return compositeConstraint;
    }
    if (!constraint) {
        newConstraint.delegate = self;
        [self.constraints addObject:newConstraint];
    }
    return newConstraint;
}

- (JRMASConstraint *)addConstraintWithAttributes:(JRMASAttribute)attrs {
    __unused JRMASAttribute anyAttribute = (JRMASAttributeLeft | JRMASAttributeRight | JRMASAttributeTop | JRMASAttributeBottom | JRMASAttributeLeading
                                          | JRMASAttributeTrailing | JRMASAttributeWidth | JRMASAttributeHeight | JRMASAttributeCenterX
                                          | JRMASAttributeCenterY | JRMASAttributeBaseline
#if TARGET_OS_IPHONE || TARGET_OS_TV
                                          | JRMASAttributeLeftMargin | JRMASAttributeRightMargin | JRMASAttributeTopMargin | JRMASAttributeBottomMargin
                                          | JRMASAttributeLeadingMargin | JRMASAttributeTrailingMargin | JRMASAttributeCenterXWithinMargins
                                          | JRMASAttributeCenterYWithinMargins
#endif
                                          );
    
    NSAssert((attrs & anyAttribute) != 0, @"You didn't pass any attribute to make.attributes(...)");
    
    NSMutableArray *attributes = [NSMutableArray array];
    
    if (attrs & JRMASAttributeLeft) [attributes addObject:self.view.JRMAS_left];
    if (attrs & JRMASAttributeRight) [attributes addObject:self.view.JRMAS_right];
    if (attrs & JRMASAttributeTop) [attributes addObject:self.view.JRMAS_top];
    if (attrs & JRMASAttributeBottom) [attributes addObject:self.view.JRMAS_bottom];
    if (attrs & JRMASAttributeLeading) [attributes addObject:self.view.JRMAS_leading];
    if (attrs & JRMASAttributeTrailing) [attributes addObject:self.view.JRMAS_trailing];
    if (attrs & JRMASAttributeWidth) [attributes addObject:self.view.JRMAS_width];
    if (attrs & JRMASAttributeHeight) [attributes addObject:self.view.JRMAS_height];
    if (attrs & JRMASAttributeCenterX) [attributes addObject:self.view.JRMAS_centerX];
    if (attrs & JRMASAttributeCenterY) [attributes addObject:self.view.JRMAS_centerY];
    if (attrs & JRMASAttributeBaseline) [attributes addObject:self.view.JRMAS_baseline];
    
#if TARGET_OS_IPHONE || TARGET_OS_TV
    
    if (attrs & JRMASAttributeLeftMargin) [attributes addObject:self.view.JRMAS_leftMargin];
    if (attrs & JRMASAttributeRightMargin) [attributes addObject:self.view.JRMAS_rightMargin];
    if (attrs & JRMASAttributeTopMargin) [attributes addObject:self.view.JRMAS_topMargin];
    if (attrs & JRMASAttributeBottomMargin) [attributes addObject:self.view.JRMAS_bottomMargin];
    if (attrs & JRMASAttributeLeadingMargin) [attributes addObject:self.view.JRMAS_leadingMargin];
    if (attrs & JRMASAttributeTrailingMargin) [attributes addObject:self.view.JRMAS_trailingMargin];
    if (attrs & JRMASAttributeCenterXWithinMargins) [attributes addObject:self.view.JRMAS_centerXWithinMargins];
    if (attrs & JRMASAttributeCenterYWithinMargins) [attributes addObject:self.view.JRMAS_centerYWithinMargins];
    
#endif
    
    NSMutableArray *children = [NSMutableArray arrayWithCapacity:attributes.count];
    
    for (JRMASViewAttribute *a in attributes) {
        [children addObject:[[JRMASViewConstraint alloc] initWithFirstViewAttribute:a]];
    }
    
    JRMASCompositeConstraint *constraint = [[JRMASCompositeConstraint alloc] initWithChildren:children];
    constraint.delegate = self;
    [self.constraints addObject:constraint];
    return constraint;
}

#pragma mark - standard Attributes

- (JRMASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
    return [self constraint:nil addConstraintWithLayoutAttribute:layoutAttribute];
}

- (JRMASConstraint *)left {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeLeft];
}

- (JRMASConstraint *)top {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeTop];
}

- (JRMASConstraint *)right {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeRight];
}

- (JRMASConstraint *)bottom {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeBottom];
}

- (JRMASConstraint *)leading {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeLeading];
}

- (JRMASConstraint *)trailing {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeTrailing];
}

- (JRMASConstraint *)width {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeWidth];
}

- (JRMASConstraint *)height {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeHeight];
}

- (JRMASConstraint *)centerX {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeCenterX];
}

- (JRMASConstraint *)centerY {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeCenterY];
}

- (JRMASConstraint *)baseline {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeBaseline];
}

- (JRMASConstraint *(^)(JRMASAttribute))attributes {
    return ^(JRMASAttribute attrs){
        return [self addConstraintWithAttributes:attrs];
    };
}

#if TARGET_OS_IPHONE || TARGET_OS_TV

- (JRMASConstraint *)leftMargin {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeLeftMargin];
}

- (JRMASConstraint *)rightMargin {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeRightMargin];
}

- (JRMASConstraint *)topMargin {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeTopMargin];
}

- (JRMASConstraint *)bottomMargin {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeBottomMargin];
}

- (JRMASConstraint *)leadingMargin {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeLeadingMargin];
}

- (JRMASConstraint *)trailingMargin {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeTrailingMargin];
}

- (JRMASConstraint *)centerXWithinMargins {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeCenterXWithinMargins];
}

- (JRMASConstraint *)centerYWithinMargins {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeCenterYWithinMargins];
}

#endif


#pragma mark - composite Attributes

- (JRMASConstraint *)edges {
    return [self addConstraintWithAttributes:JRMASAttributeTop | JRMASAttributeLeft | JRMASAttributeRight | JRMASAttributeBottom];
}

- (JRMASConstraint *)size {
    return [self addConstraintWithAttributes:JRMASAttributeWidth | JRMASAttributeHeight];
}

- (JRMASConstraint *)center {
    return [self addConstraintWithAttributes:JRMASAttributeCenterX | JRMASAttributeCenterY];
}

#pragma mark - grouping

- (JRMASConstraint *(^)(dispatch_block_t group))group {
    return ^id(dispatch_block_t group) {
        NSInteger previousCount = self.constraints.count;
        group();

        NSArray *children = [self.constraints subarrayWithRange:NSMakeRange(previousCount, self.constraints.count - previousCount)];
        JRMASCompositeConstraint *constraint = [[JRMASCompositeConstraint alloc] initWithChildren:children];
        constraint.delegate = self;
        return constraint;
    };
}

@end
